import { InjectRepository } from "@nestjs/typeorm";
import { In, Repository, TreeRepository } from "typeorm";
import { MenuClosure, MenuEntity, RoleEntity, RoleMenuEntity, UserEntity, UserRoleId } from "./entity/user.entity";
import { LoginDto } from "./dto/loginDto";
import { MenuHandle } from 'src/modules/system/menu/entity/handle.entity'
import { Injectable } from "@nestjs/common";
import { MenuGtag } from "../system/menu/entity/menuGtag.entity";
import { OrgEntity } from "./entity/org.entity";

@Injectable()
export class LoginRepository {

  constructor(
    @InjectRepository(UserEntity) private readonly userRepository: Repository<UserEntity>,
    @InjectRepository(MenuEntity) private readonly menuRepository: TreeRepository<MenuEntity>,
    @InjectRepository(MenuHandle) private readonly handleRepository: Repository<MenuHandle>,
    @InjectRepository(OrgEntity) private readonly orgRepository: Repository<OrgEntity>
  ) { }

  /**
   * 查询用户信息
   * @param userDto 用户信息
   */
  verifierPassword(userDto: LoginDto): Promise<UserEntity | null> {
    return this.userRepository
      .createQueryBuilder('user')
      .innerJoinAndSelect(
        UserRoleId, 'userRole', 'user.id = userRole.userId'
      ).leftJoinAndMapMany(
        'user.roles', RoleEntity, 'role', 'role.id = userRole.roleId'
      ).where(
        "user.loginName = :loginName", { loginName: userDto.loginName }
      ).andWhere(
        "user.password = :password", { password: userDto.password }
      ).andWhere(
        "user.delete_flag = :delete_flag", { delete_flag: false }
      ).select([
        'user.id', 'user.userName', 'user.loginName', 'user.orgId', 'role.id', 'role.roleName'
      ]).getOne();
  }

  /**
   * 查询用户菜单权限
   * @param roles 角色ID数组
   * @returns 菜单数据(非树形)
   */
  async getMenuList(roles: RoleEntity[]): Promise<MenuEntity[]> {

    const roleIds = roles.map(item => item.id)

    return this.menuRepository
      .createQueryBuilder('menu')
      .leftJoin(
        MenuClosure, 'menuClosure', 'menu.id = menuClosure.descendantId'
      )
      .leftJoin(
        RoleMenuEntity, 'roleMenu', 'menu.id = roleMenu.menuId'
      )
      .addSelect('menuClosure.ancestorId', 'menu_parentId')
      .where(`roleMenu.role_id in (${roleIds})`)
      .andWhere(
        "menu.delete_flag = :delete_flag", { delete_flag: false }
      )
      .getMany();
  }

  /**
   * 查询指定组织及所有下级组织
   * @param orgId 组织Id
   * @returns 扁平数组
   */
  getOrgTree(orgId: number | null = null): Promise<{ id: number; orgName: string }[]> {
    return this.orgRepository.query(`
      WITH RECURSIVE descendants AS (
	      SELECT d.id,d.org_name,e.ancestor_id from test_org d LEFT JOIN test_org_closure e on d.id = e.descendant_id where d.id = $1
	      UNION ALL
	      select a.id,a.org_name,b.ancestor_id from test_org a INNER JOIN test_org_closure b ON a.id = b.descendant_id INNER JOIN descendants c on c.id = b.ancestor_id
	    ) SELECT ID,org_name as orgName,ancestor_id FROM descendants
      `, [orgId])
  }

  /**
   * 查询指定组织下所有用户Id
   * @param orgId 组织ID
   * @returns 用户Ids
   */
  async getOrgUserIds(orgId: number): Promise<number[]> {

    const orgIds = (await this.getOrgTree(orgId)).map(item => item.id)

    const result = await this.userRepository.find({
      where: {
        orgId: In(orgIds),
        delete_flag: false
      }
    })

    return result.map(item => item.id)
  }

  /**
   * 获取操作权限
   * @param menuIds 菜单ID数组
   * @returns 操作按钮Code
   */
  async getHandlePermission(roleIds: number[], menuIds: number[]) {
    const result = await this.handleRepository
      .createQueryBuilder('handle')
      .innerJoin(
        MenuGtag, 'gtag', 'handle.id = gtag.handleId'
      )
      .where("handle.delete_flag = false")
      .andWhere(`gtag.menuId in (${menuIds})`)
      .andWhere(`gtag.roleId in (${roleIds})`)
      .getMany()

    return result.map(item => item.code)
  }
}